function get(id)
{
	return document.getElementById(id);
}

function disabled()
{
	// 返回 false 以禁用内容修改
	return false;
}

function keybd_press()
{
	// 切换按键状态
	this.setAttribute('key-pressed', this.getAttribute('key-pressed') == '0' ? '1' : '0');

	refresh();
}

function portbit_onclick()
{
	// 切换该位输出电平
	this.setAttribute('low', this.getAttribute('low') == '0' ? '1' : '0');

	refresh();
}

function input_change()
{
	var num = Number(this.value);
	if(!this.value || isNaN(num))
	{
		this.value = '0xff';
		return;
	}

	num = Math.floor(num);
	this.value = '0x' + ('0' + num.toString(16)).substr(-2);

	for(var i = 0; i < 8; i ++)
	{
		portbits[i].setAttribute('low', (num & 1) ? '0' : '1');
		num >>= 1;
	}

	refresh();
}

function initKeybd()
{
	var o = get('keyboard');
	keyboard = Array.from(o.children);

	keyboard.forEach((key, i) => {
		key.setAttribute('title', '点击以切换按键状态');
		key.setAttribute('key-pressed', '0');
		// 切换按键状态
		key.onclick = keybd_press;
		// 与接线关联
		key.wires = [
			wires[7 - (i >> 2)],
			wires[3 - (i & 3)]
		];
	});
}

function initWires()
{
	var o = get('wire');
	wires = Array.from(o.children).reverse();

	wires.forEach((wire) => {
		wire.setAttribute('low', '0');
	});
}

function initPortbits()
{
	var o = get('port-bit');
	portbits = Array.from(o.children).reverse();

	portbits.forEach((bit, i) => {
		bit.setAttribute('title', '点击切换该位输出电平');
		bit.setAttribute('low', '0');
		// 切换位输出状态
		bit.onclick = portbit_onclick;
		// 与接线关联
		bit.wire = wires[i];
		wires[i].bit = bit;
	});
}

function initIO()
{
	io.in = get('p1-in');
	io.in.span = get('p1-in-span');
	io.out = get('p1-out');
	io.out.span = get('p1-out-span');

	Array.from(io.in.span.children).concat(Array.from(io.out.span.children)).forEach((bit) => {
		bit.className = 'binary';
		bit.setAttribute('low', '0');
	});

	io.in.onchange = input_change;
	io.out.onkeypress = disabled;
	io.out.onchange = refreshOutput;
	io.in.span.onclick = () => {
		io.in.value = '0xff';
		io.in.onchange();
	};
}

function initButtons()
{
	buttons.reset = get('reset-button');
	buttons.revert = get('revert-button');
	buttons.swap = get('swap-button');
	buttons.reverse = get('reverse-button');

	buttons.reset.onclick = () => {
		// 重置按键状态
		keyboard.forEach((key) => key.setAttribute('key-pressed', '0'));
		refresh();
	};

	buttons.revert.onclick = () => {
		// 反置按键状态
		keyboard.forEach((key) => key.onclick());
		refresh();
	};

	buttons.swap.onclick = (click) => {
		// 交换端口行列
		if(click.shiftKey)
		{
			// 完全交换
			io.in.value = '0b' + ('0'.repeat(7) + Number(io.in.value).toString(2)).substr(-8).split('').reverse().join('');
		}
		else
		{
			// 半交换
			io.in.value = '0x' + io.in.value.substr(-2).split('').reverse().join('');
		}
		io.in.onchange();
	};

	buttons.reverse.onclick = () => {
		// 端口输出反相
		io.in.value = (~Number(io.in.value)) & 0xff;
		io.in.onchange();
	};
}

function refresh()
{
	// 重载输入
	loadInput();
	// 刷新键盘
	refreshKeybd();
	// 刷新位电平
	refreshBits();
	// 刷新输入输出
	refreshOutput();
}

function loadInput()
{
	var num = 0;
	for(var i = 0; i < 8; i ++)
	{
		let span_bit = io.in.span.children[7 - i];
		num >>= 1;
		if(portbits[i].getAttribute('low') == '1')
		{
			span_bit.setAttribute('low', '1');
			span_bit.innerHTML = '0';
		}
		else
		{
			num |= 0x80;
			span_bit.setAttribute('low', '0');
			span_bit.innerHTML = '1';
		}
	}
	io.in.value = '0x' + ('0' + num.toString(16)).substr(-2);
}

function refreshKeybd()
{
	keyboard.forEach((key) => {
		if(key.getAttribute('key-pressed') == '1')
		{
			key.src = './img/button-pressed.png';
		}
		else
		{
			key.src = './img/button-released.png';
		}
	});
}

function refreshBits()
{
	portbits.forEach((bit) => {
		bit.wire.setAttribute('low', bit.getAttribute('low'));
	});

	var ctr;
	do
	{
		ctr = 0;
		keyboard.forEach((key) => {
			if(key.getAttribute('key-pressed') == '1')
			{
				let low = key.wires.some((wire) => wire.getAttribute('low') == '1');
				if(low)
				{
					key.wires.forEach((wire) => {
						if(wire.getAttribute('low') != '1')
						{
							wire.setAttribute('low', '1');
							ctr ++;
						}
					});
				}
			}
		});
	} while(ctr);
}

function refreshOutput()
{
	var num = 0;
	for(var i = 0; i < 8; i ++)
	{
		let span_bit = io.out.span.children[7 - i];
		num >>= 1;
		if(wires[i].getAttribute('low') == '1')
		{
			span_bit.setAttribute('low', '1');
			span_bit.innerHTML = '0';
		}
		else
		{
			num |= 0x80;
			span_bit.setAttribute('low', '0');
			span_bit.innerHTML = '1';
		}
	}
	io.out.value = '0x' + ('0' + num.toString(16)).substr(-2);
}
